<?php
/**
 * @package payma
 * @subpackage includes
 * @author Ricardo Santillán Reyes
 * @copyright (c) Instituto Tecnológico de Jiquilpan
 * @license Vea LICENCIA en el directorio raiz de este proyecto
 * @date Noviembre-Diciembre 2008
 * 
 */

class BaseDatos{
	/** @var String Variable para la consulta SQL */
 	var $_sql='';
 	/** @var int Variable que almacena el numero de error de la base de datos */
 	var $_errorNum=0;
 	/** @var String Variable que guarda la descripcion del error */
 	var $_errorMsg='';
 	/** @var String Variable para el prefijo de la tablas */
 	var $_bdPrefijo='';
 	/** @var Id de el enlace a la base de datos */
 	var $_bdEnlace='';
 	/** @var Variable para mantener el recurso de la ultima consulta SQL */
 	var $_bdCursor=null;
 	/** @var boolean Opcion para llevar un registro de las consultas */
 	var $_debug=0;
 	/** @var array Registro de las consultas a las bases de datos */
 	var $_log=array();
 	/** @var String Variable que almacena el valor de una fecha nula (date/time) */
 	var $_fecha_nula='00-00-0000 00:00:00';
 	

 	/**
 	 * Constructor de la base de datos
 	 * @param String host Servidor de base de datos
 	 * @param String usuario Nombre de la base de datos
 	 * @param String pwd Contrasena del usuario de la base de datos
 	 * @param String bd Nombre de la base de datos
 	 * @param String prefijo Prefijo de las tablas de la base de datos
 	 */ 	
 	function BaseDatos($host='localhost',$usuario='root',$pwd='',$bd,$prefijo){
 		global $configuracion,$charset;
 		//Conjunto de caracteres de mysql, temporalmente, solo latin1 espanol
 		$mysql_charsets['latin1']='iso-8859-1';
 		//Verificamos que la funcion mysql_connect exista
 		if (!function_exists( 'mysql_connect' )) { $this->_errorMsg=__('PHP no soporta conexiones a MySql.'); $this->desconectado(1);}
 		//Intentamos conectar,si lo logramos asignamos el enlace a la variable publica local _bdEnlace
		if (!($this->_bdEnlace = @mysql_connect($host,$usuario,$pwd))){ $this->_errorMsg=__('No se ha podido conectar con la base de datos. Revise si el servidor MySql esta funcionando o si los parametros son correctos.'); $this->desconectado(2);}
		//Seleccionamos la base de datos
		if (!@mysql_select_db($bd,$this->_bdEnlace)){ $this->_errorMsg=__('No existe la base de datos en el servidor MySql. Revise si los parametros son correctos o pongase en contacto con el administrador.'); $this->desconectado(3);}
		$this->_bdPrefijo = $prefijo;
		//Si la version de mysql es mayor a 4.1 configuramos el 'charset'
		if(floatval(mysql_get_client_info())>=4.1){
			$charset=isset($charset)?$charset:'latin1';
			$charset = isset($configuracion)?$configuracion->charset:$charset;
			$cs=$mysql_charsets[$charset];
			mysql_query( "SET CHARSET '" .$cs. "'" );
		}
 	}
 	
 	/**
 	 * Muestra una pagina de error al usuario
 	 * @param int Numero de error
 	 */
 	function desconectado($pErrorNum){
 		$this->_errorNum = $pErrorNum; 	
		$rutaBase = dirname( __FILE__ );
		include $rutaBase . '/../config.php';
		include $rutaBase . '/../offline.php';
		exit();
 	}
 	
 	/**
 	 * Devuelve el numero de error de la clase.
 	 * @return int Numero de error de la clase.
 	 */
 	function getNumeroError(){
 		return $this->_errorNum;
 	}
 	
 	/**
 	 * Establece el nivel de depuracion
 	 * @param int Nivel de depuracion
 	 */
 	function debug($pDebug=0){
 		$this->_debug=$pDebug;
 	}
 	
 	/**
 	 * Seguimiento de errores. Se muestran los mensajes a nivel de advertencia al usuario.
 	 */
 	function debug_trace(){
		trigger_error( $this->_errorNum, E_USER_NOTICE );
		//echo "<pre>" . $this->_sql . "</pre>\n";
		if (function_exists('debug_backtrace')) {
			foreach(debug_backtrace() as $back) {
			    if (@$back['file']) {
				    echo '<br />'.$back['file'].':'.$back['line'];
				}
			}
		}
	}
	
 	/**
 	 * Devuelve el �ltimo mensaje de error de la clase.
 	 * @return String Descripci�n del error.
 	 */
 	function getMensajeError(){
 		return str_replace( array( "\n", "'" ), array( '\n', "\'" ), $this->_errorMsg );
 	}
 	
 	/**
 	 * Establece la consulta SQL a ser ejecutada despues.
 	 * @param String Consulta Sql.
 	 * @param String Prefijo de las tablas.
 	 */
 	function setConsultaPrefijo($pSql,$pPrefijo='#__'){
 		$this->setConsulta($this->replacePrefix($pSql, $pPrefijo));
 	}
 	/**
 	 * Establece la consulta SQL a ser ejecutada despues.
 	 * @param String Consulta Sql.
 	 */
 	function setConsulta($pSql){
 		$this->_sql=$pSql;
 	}
 	
 	/**
	* Obtiene el escaped de la base de datos
	* @return string
	*/
	function getEscaped( $texto ) {
	    if (phpversion() < '4.3.0') {
	        return mysql_escape_string( $texto );
	    } else {
	        return mysql_real_escape_string( $texto );
	    }
	}
 	
 	/**
	 * This function replaces a string identifier <var>$prefix</var> with the
	 * string held is the <var>_table_prefix</var> class variable.
	 *
	 * @param string The SQL query
	 * @param string The common table prefix
	 * @author thede, David McKinnis
	 */
	function replacePrefix ($sql, $prefix='#__') {
		$done = '';
		while (strlen($sql)) {
			$single = preg_match("/\'([^\\\']|\\.)*'/", $sql,$matches_single,PREG_OFFSET_CAPTURE);
			if ($double = preg_match('/\"([^\\\"]|\\.)*"/', $sql,$matches_double,PREG_OFFSET_CAPTURE) OR $single) {
				if ($single == 0 OR ($double AND $matches_double[0][1] < $matches_single[0][1])) {
					$done .= str_replace($prefix, $this->_bdPrefijo, substr($sql,0,$matches_double[0][1])).$matches_double[0][0];
					$sql = substr($sql,$matches_double[0][1]+strlen($matches_double[0][0]));
				}
				else {
					$done .= str_replace($prefix, $this->_bdPrefijo, substr($sql,0,$matches_single[0][1])).$matches_single[0][0];
					$sql = substr($sql,$matches_single[0][1]+strlen($matches_single[0][0]));
				}
			}
			else return $done.str_replace($prefix, $this->_bdPrefijo,$sql);
		}
		return $done;
	}
	
	/**
	 * Devuelve la consulta sql (interna o dada en <var>$pSql</var>) para ser impresa.
	 * @param String (opcional) La consulta SQL a ser impresa.
	 * @return string La consulta SQL para ser impresa.
	 */
	function getConsulta($pSql='') {
		if ($pSql == '') $pSql = $this->_sql;
		return "<pre>" . htmlspecialchars( $pSql ) . "</pre>";
	}
	
	/**
	 * Ejecuta una consulta SQL
	 * @param String (opcional) Consulta sql a realizar.
	 * @return mixed false; Si no se ejecuta correctamente. recurso; Si la consulta fue correcta.
	 */
	function consulta($pSql = '') {
		if ($pSql == '') $pSql = $this->_sql;
		if ($this->_debug) $this->_log[] = $pSql; //Si esta establecido el debug guardamos agregamos a el log la consulta.
		if ($this->_bdCursor = @mysql_query($pSql, $this->_bdEnlace)) {
			$this->_errorNum = 0;
			$this->_errorMsg = '';
			return $this->_bdCursor;
		}else {
			$this->_errorNum = @mysql_errno( $this->_bdEnlace );
			$this->_errorMsg = @mysql_error( $this->_bdEnlace );//." SQL=$pSql";
			if ($this->_debug) $this->debug_trace(); //Si el modo debug est� habilitado mostramos un mensaje de advertencia al usuario.
			return false;
		}
	}

    /**
     * Ejecuta una consulta SQL con prefijos
     * @param String COnsulta con prefijos a realizar
     * @return mixed false; si no se ejecuta correctamente. recurso; Si la consulta fue correcta.
     */
    function consultaPrefijo($pSql){
        $this->setConsultaPrefijo($pSql);
        return $this->consulta();
    }

	/**
	 * Obtiene el n�mero total de filas en la consulta.
	 * @param cursor (opcional) El cursor de la consulta
	 * @return int N�mero de filas en la consulta.
	 */
	function getNumeroFilas($pCursor=null){
		return @mysql_num_rows($pCursor ? $pCursor : $this->_bdCursor);
	}
	
	/**
	 * Obtiene el n�mero total de filas afectadas en la consulta.
	 * @return int N�mero de filas afectadas en la �ltima consulta SQL.
	 */
	function getFilasAfectadas(){
		return @mysql_affected_rows($this->_bdEnlace);
	}
	
	/**
	 * Retorna los resultados de la consulta en un arreglo
	 * por filas
	 * @param num int Posicion del campos en el arreglo
	 */
	function getResultadoFilas($num=0) {
		$resultados = $this->getResultado();
		$retorna=array();
		foreach($resultados as $resultado)
			$retorna[]=$resultado[$num];
		if (count($resultados))
			return $retorna;
		else
			return null;
	}
	
	/**
	 * Retorna un arreglo con los resultados de la consulta
	 * @param int (opcional) Numero maximo de resultados.
	 * @param String (opcional) Tipo de resultado (array,row,object).
	 * @return array Un arreglo con los resultados 
	 */
	function &getResultado($llave='',$pMax=0, $pTipoResultado='row'){
		$resultados=array();
		$funcionSql='mysql_fetch_'.$pTipoResultado;
		if ($cursor = $this->consulta()) {
			while ($fila = $funcionSql($cursor)){
				if ($llave != '') {
					if ( is_array($fila) ) {
						$resultados[$fila[$llave]] = $fila;
					} else {
						$resultados[$fila->$llave] = $fila;
					}
				} else {
					$resultados[] = $fila;
				}
				if ($pMax AND count($resultados) >= $pMax) break;
			}
			mysql_free_result($cursor);
		}
		return $resultados;
	}

	/**
	 * Obtiene todos los registros de una columna en espec�fico
	 * @param int (opcional) N�mero de columna a obtener.
	 * @return mixed array; Los registros de la columna. null; Si falla la consulta.
	 */
	function getColumna($pNumeroColumna=0){
		$resultado =& $this->getResultado();
		$valores = array();
		foreach ($resultado as $result) $valores[] = $result[$pNumeroColumna];
		if (count($valores)) return $valores;
		else return null;
	}
	
	/**
	 * Obtiene la primera fila de una consulta.
	 * @return mixed array; La primer fila. null; Si falla la consulta.
	 */
	function getPrimeraFila(){
		$resultado =& $this->getResultado('',1, 'row');
		if (count($resultado)) return $resultado[0];
		else return null;
	}
	
	/**
	 * Quita las barras(diagonales [/\]) de un arreglo o una cadena
	 * @param mixed byref Cadena o arreglo a "limpiar"
	 * @return mixed Cadena o arreglo "limpio" 
	 */
	function quitaBarras( &$pCadena ){
		if (is_string($pCadena)) $retorno = stripslashes($pCadena);
		else {
		    if (is_array($pCadena)) {
		        $retorno = array();
		        while (list($key,$val) = each($pCadena)) {
		            $retorno[$key] = $this->quitaBarras($val);
		        }
		    } else $retorno = $pCadena;
		}
	    return $retorno;
	}
	
	/**
	 * Obtiene el identificador generado en una consulta INSERT
	 * donde existe algun campo AUTO_INCREMENT
	 * @return int Identificador generado para un campo AUTO_INCREMENT en una consulta INSERT
	 */
	function getInsertId() {
		return mysql_insert_id();
	}

	/**
	 * Obtiene la versi�n de MySql
	 * @return String Versi�n de MySql
	 */
	function getVersion() {
		return mysql_get_server_info();
	}
	
	/**
	 * Obtiene un arreglo con las tablas que existen en la base de datos.
	 * @return array Lista de tablas
	 */
	function getTablas() {
		$this->setConsulta( 'SHOW tables' );
		$this->consulta();
		return $this->getResultadoFilas();
	}
	
	/**
	 * Devuelve la consulta Sql necesaria para crear las tablas dadas en <var>$pTablas</var>  
	 * @param array Nombres de las tablas
	 * @return array Consulta Sql para crear cada tabla. 
	 */
	function getSqlCrearTablas( $pTablas ) {
		$resultado = array();
		foreach ($pTablas as $tbl) {
			$this->setConsulta('SHOW CREATE table '.$tbl);
			$this->consulta();
			$resultado[$tbl] = $this->getResultadoFilas(1);
		}
		return $resultado;
	}
	
	/**
	 * Obtiene los campos que tienen las tablas
	 * @param  array Nombre de las tablas.
	 * @return array Campos de las tablas (<code>$campos['tabla']['campo']</code>)
	 */
	function getCamposTablas( $pTablas ) {
		$resultado = array();
		foreach ($pTablas as $tbl) {
			$this->setConsulta('SHOW FIELDS FROM ' . $tbl);
			$this->consulta();
			$campos = $this->loadListaObjetos();
			foreach ($campos as $campo) {
				$resultado[$tbl][$campo->Field] = preg_replace("/[(0-9)]/",'', $campo->Type );
			}
		}
		return $resultado;
	}
	
	/**
	 * Obtiene en c�digo HTML el registro de las consultas que se han realizado.
	 * @return String C�digo HTML con el registro de las consultas realizadas. 
	 */
	function getShowLog () {
		echo count($this->_log).' consultas realizadas.';
		echo '<pre>';
	 	foreach ($this->_log as $k=>$sql) {
	 	    echo $k+1 . "\n" . $sql . '<hr />';
		}
	}
	
	/**
	 * Ejecuta una consulta SQL y en caso de existir error, lo muestra como una alerta JavaScript;
	 * adem�s redirecciona al navegador a una p�gina antes. 
	 * @param String Consulta SQL
	 */
	function consultaConAlerta($pSql){
		$this->setConsulta($pSql);
		if (!$this->consulta()) {
			echo "<script> alert('".$this->getMensajeError()."'); window.history.go(-1); </script>\n";
			exit();
		}
	}
	
	/** Copia el arreglo en un objeto con su contenido como propiedades.
	 * solo las propiedades existentes en el objeto son llenadas. Cuando no existen, las propiedades no son borradas.
	 * @param array El arreglo de entrada
	 * @param obj byref El objeto a llenar de cualquier clase.
	 * @param string propiedades a ignorar
	 * @param string Prefijo
	 * @param boolean Revisa las "barras"
	 */
	function arrayToObjeto( $array, &$obj, $ignora='', $prefijo=NULL, $revisaBarras=true ) {
		if (!is_array($array) OR !is_object($obj)) return false;
		if ($prefijo == null) $prefijo = '';
		foreach (get_object_vars($obj) as $k => $v) {
			if( substr( $k, 0, 1 ) != '_' AND strpos($ignora, $k) === false) {
				if (isset($array[$prefijo.$k])) {
					$obj->$k = ($revisaBarras AND get_magic_quotes_gpc()) ? $this->quitaBarras( $array[$prefijo.$k] ) : $array[$prefijo.$k];
				}
			}
		}
		return true;
	}
	
	/** Carga la primera fila de un consulta en un objeto.
	 * Si un objeto es recibido,  se retornaran solo los elementos existentes en el.
	 * Si el objeto recivido esta vacio, todos los campos devueltos por la consulta seran las propiedades del objeto
	 * 
	 * @param object byref Direccion del objeto (nulo o inicializado)
	 * @return bool  
	 */
	function loadObjeto( &$obj ) {
		if ($obj != null) {
			$resultados =& $this->getResultado('', 1, 'assoc');
			if (count($resultados)) {
				$this->arrayToObjeto($resultados[0], $obj, null, null, false);
				return true;
			}
		}else{
			$resultados =& $this->getResultado('', 1, 'object');
			if (count($resultados)) {
				$obj = $resultados[0];
				return true;
			}
			else $obj = null;
		}
		return false;
	}
	
	
	/**
	 * Inserta las propiedades de un objeto en la base de datos
	 * @param string La tabla de la base de datos
	 * @param object El objeto con las propiedades
	 * @param object 
	 */
	function insertObjeto( $tabla, &$objeto, $clave = NULL, $verbose=false ) {
		$sql = "INSERT INTO $tabla ( %s ) VALUES ( %s ) ";
		$sql = $this->replacePrefix($sql);
		$fields = array();
		foreach (get_object_vars( $objeto ) as $k => $v) {
			if (is_array($v) OR is_object($v) OR $v === NULL OR $k[0] == '_') continue;
			$fields[] = "`$k`";
			$values[] = "'" . $this->getEscaped($v) . "'";
		}
		if (!isset($fields)) die ('insertObject de la base de datos, no tiene campos');
		$this->setConsulta( sprintf( $sql, implode( ",", $fields ), implode( ",", $values ) ) );
		($verbose) && print "$sql<br />\n";
		if (!$this->consulta()) return false;
		$id = $this->getInsertId();
		($verbose) && print "id=[$id]<br />\n";
		if ($clave && $id) $objeto->$clave = $id;
		return true;
	}
	
	/** Carga una lista de los objetos de la base de datos.
	 * @param string El nombre de la llave primaria.
	 * @return array Si el parametro esta vacio se retorna una lista de los elementos.
	 * Si no, devuelve un arreglo indexado por la llave primaria.
	 * Regresa nulo si la consulta falla
	 */
	function loadListaObjetos( $key='' ) {
		$resultados =& $this->getResultado($key,0, 'object');
		if (count($resultados)) return $resultados;
		else return null;
	}
	
	/**
	 * Actualiza un objeto en la tabla
	 * @param string El nombre de la tabla
	 * @param object El objeto que sera actualizado
	 * @param int LLave primaria para identificar la fila a actualizar
	 * @param boolean False; Si existe algun valor nulo en el objeto lo omite 
	 */
	function updateObjeto( $tabla, &$objeto, $clave, $updateNulls=true ) {
		$sql = "UPDATE $tabla SET %s WHERE %s";
		$sql = $this->replacePrefix($sql);
		$tmp = array();
		foreach (get_object_vars( $objeto ) as $k => $v) {
			if (is_array($v) OR is_object($v) OR $k[0] == '_' OR ($v === null AND !$updateNulls)) continue;
			if( $k == $clave ) { // La clave principal no se actualiza
				$where = "$clave='" . $this->getEscaped($v) . "'";
				continue;
			}
			if ($v) $v = $this->getEscaped($v);
			$tmp[] = "`$k`='$v'";
		}
		if (!isset($tmp)) return true;
		if (!isset($where)) die ('La clase updateObjeto de la base de datos, no tiene valor de la clave');
		$this->setConsulta( sprintf( $sql, implode( ",", $tmp ) , $where ) );
		return $this->consulta();
	}
	
	/**
	 * Ejecuta una sentencia SQL y si existe error, muestra un mensaje javascript
	 * @param Consulta SQL
	 */
	function doSQL ($sql) {
		$this->setConsulta($sql);
		if (!$this->consulta()) {
			echo "<script> alert('".$this->getMensajeError()."'); window.history.go(-1); </script>\n";
			exit();
		}
	}
	
	/**
	 * Ejecuta una consulta SQL y la devuelve como una clase
	 * @param string Consulta SQL
	 * @param string Nombre de la clase
	 */
	function &doSQLget ($sql, $classname) {
		$this->setConsulta($sql);
		$rows = $this->loadListaObjetos();
		$target = get_class_vars($classname);
		if ($rows) {
			foreach ($rows as $row) {
				$next = new $classname(0);
				foreach ($target as $field=>$value) {
					if (isset($row->$field)) $next->$field = $row->$field;
				}
				$result[] = $next;
			}
		}
		else $result = array();
		return $result;
	}
	
	/**
	 * @param boolean Si es verdadero, muestra la ultima consulta enviada a la base de datos.
	 * @return string Mensaje de error
	 */
	function stderr( $muestraSQL = false ) {
		return __('La base de datos fallo con el numero de error'). ' '.$this->_errorNum
		."<br />".__('MySql dice:')."&nbsp;&nbsp;<font color=\"red\">$this->_errorMsg</font>"
		.($muestraSQL ? "<br />".__('Codigo SQL:')."<hr /><pre>$this->_sql</pre>" : '');
	}
}

class MainBaseDatos extends BaseDatos {

	function MainBaseDatos () {
		$host = Clases::get('host');
		$usuario = Clases::get('usuario');
		$pwd = Clases::get('password');
		$bd = Clases::get('nombre');
		$prefijo = Clases::get('prefijo');
		parent::BaseDatos($host, $usuario, $pwd, $bd, $prefijo);
	}

	static function &getMainBaseDatos () {
		static $instancia;
		if (!is_object($instancia)) $instancia = new MainBaseDatos();
		return $instancia;
	}
}

/**
 * Clase que permite hacer operaciones con filas
 * @author Martin Brampton <counterpoint@mambo-foundation.org>
 * @author Ricardo Santillan <hipnoss@gmail.com> (Traduccion & adaptacion)
 */
 class Fila {
	/** @var string Nombre de la tabla en la base de datos */
	var $_tabla = '';
	/** @var string Nombre de la llave primaria en la tabla */
	var $_llave_tabla = '';
	/** @var string Mensaje de error */
	var $_error = '';

	/**
	 * Constructor, establece el nombre de la tabla y la llave primaria
	 * @param string Nombre de la tabla en la base de datos
	 * @param string Nombre de la llave primaria en la tabla
	 */
	function Fila ($tabla='', $primaria='id', $bd='') {
		if ($tabla) $this->_tabla = $tabla;
		else $this->_tabla = $this->nombreTabla();
		$this->_llave_tabla = $primaria;
		if (is_object($bd)) $this->_bd = $bd;
	}

	/**
	 * Revisa que el objeto se haya construido bien
	 * @return boolean True si el objeto esta bien
	 */
	function revisa() {
		return true;
	}

	/**
	 * Revisa si el objeto soporta la propiedad dada en el parametro
	 * @param string Nombre de la propiedad
	 * @return boolean True si no lo soporta
	 */
	function lacks( $propiedad ) {
		$estaclase = get_class($this);
		if (array_key_exists( $propiedad, get_class_vars($estaclase) )) return false;
		$this->_error = __(sprintf('Advertencia: %s no soporta %s.', $estaclase, $propiedad));
		return true;
	}

	/**
	 * Mueve una fila arriba o abajo atravez de 'orderin'
	 * @param int Entero positivo para mover arriba, negativo para abajo.
	 * @param string Condiciones adicionales en la clausula WHERE para limitar el efecto.
	 */
	function move( $direccion, $where='' ) {
		global $basedatos; 
		$compops = array (-1 => '<', 0 => '=', 1 => '>');
		$relacion = $compops[($direccion>0)-($direccion<0)];
		$orden = ($relacion == '<' ? 'DESC' : 'ASC');
		$k = $this->_llave_tabla;
		$o1 =$orden;
		$k1 = $this->$k;
		$basedatos = isset($this->_bd) ? $this->_bd : MainBaseDatos::getMainBaseDatos();
		//TODO CAMPO orden EN LAS TABLAS
		$sql = "SELECT $k, orden FROM $this->_tabla WHERE orden $relacion $o1";
		$sql .= ($where ? "\n AND $where" : '').' ORDER BY orden '.$orden.' LIMIT 1';
		$basedatos->setConsulta( $sql );
		if ($basedatos->loadObjeto($row=null)) {
			$o2 = $row->orden;
			$k2 = $row->$k;
			$sql = "UPDATE $this->_tabla SET orden = (orden=$o1)*$o2 + (orden=$o2)*$o1 WHERE $k = $k1 OR $k = $k2";
			$basedatos->doSQL($sql);
		}
	}
	
	/**
	* Comprime la secuencia de ordenado de los registros seleccionados
	* @param string Condiciones adicionales en la clausula where para limitar el efecto del ordenamiento
	*/
	function updateOrden( $where='', $cfid=null, $orden=null ) {
		if ($this->lacks('orden')) return false;
		$k = $this->_llave_tabla;
		if ($this->_tabla == "#__pagina_frente") $orden2 = ", id_contenido DESC";
		else $orden2 = "";

		$basedatos = isset($this->_bd) ? $this->_bd : MainBaseDatos::getMainBasedatos();
		
		if (!is_null($cfid) AND !is_null($orden)) {
			foreach ($cfid as $i=>$id) {
				$o = intval($orden[$i]);
				$set[] = "(id=$id)*$o";
			}
			$sql = "UPDATE $this->_tabla SET orden = ".implode(' + ', $set).' WHERE id IN ('.implode(',', $cfid).')';
			$basedatos->doSQL($sql);
		}
		
		$sql = "SELECT $k, orden FROM $this->_tabla "
		. ($where ? "\nWHERE $where" : '')
		. "\nORDER BY orden$orden2";
		$basedatos->setConsulta($sql);
		if (!$rows = $basedatos->loadListaObjetos()) {
			$this->_error = $basedatos->getMensajeError();
			return false;
		}
		$i = 1;
		foreach ($rows as $row) {
			$sql = "UPDATE $this->_tabla SET orden=$i WHERE $k = ".$row->$k;
			$basedatos->doSQL($sql);
			$i++;
		}
		return true;
	}
}

/**
 * Clase que realiza operaciones con filas
 */
class Tabla extends Fila{
	/** @var object Cursor a la base de datos */
	var $_bd=null;
	
	/**
	 * Filtra las propiedades publicas
	 * @param array Lista de los campos a ignorar
	 */
	function filtro( $listaIgnora=null ) {
		//Verificamos que se puedan ejecutar
		//el filtro de campos (la clase y la funcion)
		$revisallamado = array('InputFilter', 'process');
		if (!is_callable($revisallamado)) require_once(Clases::get('ruta_absoluta').'/includes/phpInputFilter/class.inputfilter.php');
		
		$iFiltro =& new InputFilter();
		if (is_array($listaIgnora)) foreach ($this->getPropiedadesPublicas() as $k) {
			if (!in_array($k, $listaIgnora)) $this->$k = $iFiltro->process($this->$k);
		}
		else foreach ($this->getPropiedadesPublicas() as $k) $this->$k = $iFiltro->process($this->$k);
	}
	
	/**
	 *	@return string Regresa el mensaje de error
	 */
	function getError() {
		return $this->_error;
	}
	
	/**
	* Obtiene el valor de la variable de clase.
	* @param string El nombre de la variable de la clase
	* @return mixed El valor de la variable de clase (o null si la variable no existe)
	*/
	function get( $propiedad ) {
		if(isset( $this->$propiedad )) return $this->$propiedad;
		else return null;
	}
	
	/**
	 * Regresa un arreglo con las propiedades publicas
	 * @return array
	 */
	function getPropiedadesPublicas() {
		static $cache = null;
		if (is_null( $cache )) {
			$cache = array();
			foreach (get_class_vars( get_class( $this ) ) as $key=>$val) {
				if (substr( $key, 0, 1 ) != '_') {
					$cache[] = $key;
				}
			}
		}
		return $cache;
	}
	
	/**
	 * Establece el valor de la variable de clase
	 * @param string El nombre de la variable de clase
	 * @param mixed El valor a asignar a la variable
	 */
	function set( $propiedad, $valor ) {
		$this->$propiedad = $valor;
	}
	
	/**
	 *	Enlaza un arreglo a este objeto
	 *	@param int $oid Argumento opcional, si no esta especificado el valor de la clave actual sera usado
	 *	@return mixed Resultado de la base de datos
	 */
	function load( $oid=null ) {
		$k = $this->_llave_tabla;
		if ($oid !== null) {
			$this->$k = $this->_bd->getEscaped($oid);
		}	
		if ($this->$k === null) return false;
		$this->_bd->setConsultaPrefijo("SELECT * FROM $this->_tabla WHERE $this->_llave_tabla='".$this->$k."'" );
		return $this->_bd->loadObjeto($this);
	}

	/**
	 * Agrega una nueva fila si la id es 0, o actualiza una fila existente en la tabla de la base de datos
	 *
	 * @param boolean false; Las variables nulas no son actualizadas
	 * @return boolean
	 */
	function store( $updateNulls=false ) {
		$k = $this->_llave_tabla;
		global $migrar;
		if( $this->$k && !$migrar) $ret = $this->_bd->updateObjeto( $this->_tabla, $this, $this->_llave_tabla, $updateNulls );
		else $ret = $this->_bd->insertObjeto( $this->_tabla, $this, $this->_llave_tabla );
		if( !$ret ) {
			$this->_error = strtolower(get_class( $this ))."::".__('fallo el guardado'). "<br />" . $this->_db->getErrorMsg();
			return false;
		} else return true;
	}

	/**
	 *	Metodo por defecto para eliminar
	 *
	 *	@return boolean
	 */
	function delete( $oid=null ) {
		$k = $this->_llave_tabla;
		if ($oid) $this->$k = intval( $oid );
		$this->_db->setConsulta( "DELETE FROM $this->_tabla WHERE $this->_llave_tabla = '".$this->$k."'" );
		return $this->consulta();
	}
	
	/**
     * Exporta una arreglo a XML
	 * @param boolean Mapa de las claves foraneas a texto
	 */
	function toXML( $mapKeysToText=false ) {
		$xml = '<record table="' . $this->_tbl . '"';
		if ($mapKeysToText) $xml .= ' mapkeystotext="true"';
		$xml .= '>';
		foreach (get_object_vars($this) as $k => $v) {
			if ($v === null OR is_array($v) OR is_object($v)) continue;
			if ($k[0] == '_') continue; // Campo interno
			$xml .= '<' . $k . '><![CDATA[' . $v . ']]></' . $k . '>';
		}
		$xml .= '</record>';
		return $xml;
	}
}

//class EntradaTabla extends Filas{
//}
?>
